home *** CD-ROM | disk | FTP | other *** search
/ The Atari Compendium / The Atari Compendium (Toad Computers) (1994).iso / files / umich / utils / whati~gz.zoo / apropos.c < prev    next >
C/C++ Source or Header  |  1992-09-13  |  8KB  |  434 lines

  1. #undef DEBUG
  2.  
  3. /*
  4.  *    apropos - find pertinent on-line documentation
  5.  * 
  6.  *     apropos name ...
  7.  */
  8.  
  9. static char *rcsid_apropos_c = "$Id: apropos.c,v 2.0 1992/09/13 05:02:44 rosenkra Exp $";
  10. /*
  11.  * $Log: apropos.c,v $
  12.  * Revision 2.0  1992/09/13  05:02:44  rosenkra
  13.  * total rewrite. this if first rev of this file.
  14.  *
  15.  *
  16.  */
  17.  
  18. #include <stdio.h>
  19. #include <string.h>
  20. #include <stdlib.h>
  21. #include <ctype.h>
  22.  
  23.  
  24. #include "whatis.h"
  25.  
  26.  
  27. /*
  28.  *    we only need one record here. we read a record and check all the
  29.  *    command line args against it for a match
  30.  */
  31. struct rec    r;
  32.  
  33. char           *libpath = MANPATH;    /* path to database files (-P) */
  34. int        debugging = 0;        /* for -d */
  35.  
  36.  
  37. /*
  38.  *    fcn prototypes
  39.  */
  40. void        apropos (int, int, int, char **);
  41. int        match_up (char *, char *);
  42. int        advance (char *, char *);
  43. int        cmp_ign_case (int, int);
  44. void        usage (int);
  45. int        parse_record (char *, struct rec *);
  46. void        print_record (int, struct rec *);
  47. #ifdef CHECK_MAGIC
  48. int        check_magic (void);
  49. #endif
  50.  
  51.  
  52.  
  53.  
  54. /*------------------------------*/
  55. /*    main            */
  56. /*------------------------------*/
  57. void main (int argc, char *argv[])
  58. {
  59.     int    sect = -1;
  60.     int    verbose = 0;
  61.     char   *lpath;
  62.     char   *ps;
  63.  
  64.  
  65.  
  66.     /*
  67.      *   see if there is MANPATH in env. use it over default...
  68.      */
  69.     if ((lpath = getenv ("MANPATH")) != (char *) NULL)
  70.         libpath = lpath;
  71.     else if ((lpath = getenv ("MANDIR")) != (char *) NULL)
  72.         libpath = lpath;
  73. #ifdef DEBUG
  74.     else
  75.         fprintf (stderr, "apropos: environment variable MANPATH not set, using default\n");
  76. #endif
  77.  
  78.  
  79.     /*
  80.      *   parse args
  81.      */
  82.     for (argc--, argv++; argc && **argv == '-'; argc--, argv++)
  83.     {
  84.         switch (*(*argv+1))
  85.         {
  86.         case 'P':            /* path for db */
  87.         case 'M':
  88.             argc--, argv++;
  89.             if (argc < 1)
  90.                 usage (1);
  91.             libpath = *argv;
  92.             break;
  93.  
  94.         case 's':            /* specific section */
  95.             argc--, argv++;
  96.             if (argc < 1)
  97.                 usage (1);
  98.             sect = **argv;
  99.             break;
  100.  
  101.         case 'd':            /* debug mode */
  102.             debugging = 1;
  103.             break;
  104.  
  105.         case 'h':            /* help */
  106.             usage (0);
  107.             /* NOTREACHED */
  108.         }
  109.     }
  110.  
  111.  
  112.  
  113.     /*
  114.      *   apropos what?
  115.      */
  116.     if (argc == 0)
  117.     {
  118.         fprintf (stderr,
  119.         "apropos: you must specify an argument. consider using whatisin.\n");
  120.         usage (1);
  121.     }
  122.  
  123.  
  124.  
  125.     /*
  126.      *   not documented: if first arg is a number, use it for section...
  127.      */
  128.     if (isdigit(**argv))
  129.     {
  130.         sect = **argv;
  131.         argc--, argv++;
  132.     }
  133.  
  134.  
  135.  
  136.     /*
  137.      *   do it. if specific section, search it only. else search all
  138.      *   sections
  139.      */
  140.     if (sect != -1)
  141.     {
  142.         apropos (verbose, sect, argc, argv);
  143.     }
  144.     else
  145.     {
  146.         for (ps = SECTIONS; *ps; ps++)
  147.         {
  148.             sect = *ps;
  149.             apropos (verbose, sect, argc, argv);
  150.         }
  151.     }
  152.  
  153.  
  154.     exit (0);
  155. }
  156.  
  157.  
  158.  
  159. /*------------------------------*/
  160. /*    apropos            */
  161. /*------------------------------*/
  162. void apropos (int verbose, int sect, int argc, char **argv)
  163. {
  164. #define MAX_ARGS    100
  165.  
  166.     char        dbname[256];
  167.     char        buf[REC_SIZE];
  168.     char            srch[REC_SIZE];
  169.     register char **vp;
  170.     int        notfound[MAX_ARGS];
  171.     int        i, j;
  172.  
  173.  
  174.  
  175.     /*
  176.      *   FIXME: we should allocate space for the notfound list.
  177.      */
  178.     if (argc > MAX_ARGS)
  179.         argc = MAX_ARGS;
  180.  
  181.  
  182.  
  183.     /*
  184.      *   set up db name. section is really a single ascii char, not an
  185.      *   int. this is so we can have whatis for local, new, etc.
  186.      */
  187.     if (sect == -1)
  188.         /* orig behavior (just single "whatis" file, never used here) */
  189.         sprintf (dbname, "%s%s%s", libpath, SLASH, WHATIS);
  190.     else
  191.         /* new: whatis._[0-9lno]_ */
  192.         sprintf (dbname, "%s%s%s._%c_", libpath, SLASH, WHATIS, sect);
  193.  
  194.  
  195.  
  196.     /*
  197.      *   reopen stdin as this file...
  198.      */
  199.     if (debugging)
  200.         fprintf (stderr, "checking database file %s...\n", dbname);
  201.     if (freopen (dbname, "r", stdin) == (FILE *) NULL)
  202.     {
  203. /*        if (verbose || debugging)*/
  204.         if (debugging)
  205.             fprintf (stderr,
  206.                 "apropos: could not access file %s\n", dbname);
  207.  
  208.         return;
  209.     }
  210.  
  211.  
  212.  
  213.  
  214. #ifdef CHECK_MAGIC
  215.     /*
  216.      *   check file's magic
  217.      */
  218.     if (check_magic ())
  219.     {
  220.         fprintf (stderr,
  221.             "whatis: magic number is wrong for file %s\n",
  222.             dbname);
  223.  
  224.         return;
  225.     }
  226. #endif
  227.  
  228.  
  229.  
  230.  
  231.     /*
  232.      *   read file and compare. first assume we will not find anything
  233.      *   and flag list...
  234.      */
  235.     for (i = 0; i < MAX_ARGS; i++)
  236.         notfound[i] = 1;
  237.     while (1)
  238.     {
  239.         /*
  240.          *   get raw record from file
  241.          */
  242.         fgets (buf, REC_SIZE-1, stdin);
  243.         if (feof (stdin))
  244.             break;
  245.         if (debugging)
  246.             fprintf (stderr, "%s", buf);
  247.  
  248.  
  249.  
  250.         /*
  251.          *   skip comment or blank lines
  252.          */
  253.         if (buf[0] == '#' || buf[0] == '\0' || buf[0] == '\n')
  254.             continue;
  255.  
  256.  
  257.  
  258.         /*
  259.          *   parse the record and store in r
  260.          */
  261.         parse_record (buf, &r);
  262.  
  263.         if (debugging)
  264.         {
  265.         fprintf (stderr, "name:    %s\n", r.name ? r.name : "(NULL)");
  266.         fprintf (stderr, "section: %s\n", r.section ? r.section : "(NULL)");
  267.         fprintf (stderr, "subsect: %s\n", r.subsect ? r.subsect : "(NULL)");
  268.         fprintf (stderr, "desc:    %s\n", r.desc ? r.desc : "(NULL)");
  269.         }
  270.  
  271.  
  272.  
  273.         /*
  274.          *   compare record's name field to all args from orig
  275.          *   command line. if we find one, flag notfound list
  276.          */
  277.         for (i = 0, vp = argv; i < argc && *vp; vp++, i++)
  278.         {
  279.             /*
  280.              *   make a long list of things to search
  281.              */
  282.             srch[0] = '\0';
  283.             if (r.name)
  284.             {
  285.                 strcat (srch, r.name);
  286.                 strcat (srch, " ");
  287.             }
  288.             if (r.desc)
  289.             {
  290.                 strcat (srch, r.desc);
  291.                 strcat (srch, " ");
  292.             }
  293.             for (j = 0; j < MAX_ALIAS; j++)
  294.             {
  295.                 if (r.alias[j] == NULL)
  296.                     break;
  297.                 strcat (srch, r.alias[j]);
  298.                 strcat (srch, " ");
  299.             }
  300.             for (j = 0; j < MAX_KEYW; j++)
  301.             {
  302.                 if (r.keyw[j] == NULL)
  303.                     break;
  304.                 strcat (srch, r.keyw[j]);
  305.                 strcat (srch, " ");
  306.             }
  307.             
  308.  
  309.  
  310.             /*
  311.              *   check for a match...
  312.              */
  313.             if (match_up (srch, *vp))
  314.             {
  315.                 print_record (verbose, &r);
  316.                 notfound[i] = 0;
  317.             }
  318.         }
  319.     }
  320.  
  321.  
  322.  
  323.     /*
  324.      *   print a message if we didn't find anything for the cmdline arg
  325.      */
  326.     if (verbose)
  327.     {
  328.         for (i = 0; i < argc; i++)
  329.         {
  330.             if (notfound[i])
  331.             {
  332.                 printf ("nothing appropriate in section %c for %s\n",
  333.                     sect, argv[i]);
  334.             }
  335.         }
  336.     }
  337.  
  338.     return;
  339. }
  340.  
  341.  
  342.  
  343.  
  344. /*------------------------------*/
  345. /*    match_up        */
  346. /*------------------------------*/
  347. int match_up (char *buf, char *str)
  348. {
  349.  
  350. /*
  351.  *    search for string in str from a list contained in buf. this part
  352.  *    just advances a ptr to buf and calls a lower level routine. ret 1
  353.  *    if there is a match, else 0.
  354.  */
  355.  
  356.     register char  *pbuf;
  357.  
  358.     for (pbuf = buf; *pbuf; pbuf++)
  359.         if (advance (pbuf, str))
  360.             return (1);
  361.  
  362.     return (0);
  363. }
  364.  
  365.  
  366.  
  367.  
  368. /*------------------------------*/
  369. /*    advance            */
  370. /*------------------------------*/
  371. int advance (char *s1, char *s2)
  372. {
  373.  
  374. /*
  375.  *    main matching driver. advances along each string. cmp_ign_case does
  376.  *    theactual char match. ret 1 if match, else 0. search is finished when
  377.  *    s2 is at EOS.
  378.  */
  379.  
  380.     while (*s1 && *s2
  381.     && ((*s1 == *s2) || cmp_ign_case ((int) (*s1), (int) (*s2))))
  382.         s1++, s2++;
  383.  
  384.     if (*s2 == 0)
  385.         return (1);
  386.  
  387.     return (0);
  388. }
  389.  
  390.  
  391.  
  392.  
  393. /*------------------------------*/
  394. /*    cmp_ign_case        */
  395. /*------------------------------*/
  396. int cmp_ign_case (int c1, int c2)
  397. {
  398.  
  399. /*
  400.  *    char matching part. ignores case. must be alpha chars only! if
  401.  *    chars match, ret 1, else 0. c1 should probably always be alpha,
  402.  *    but check anyway. c2 comes from user. check it first for possible
  403.  *    quick exit. compare in lower case (since that is more probable
  404.  *    and the tolower could be skipped).
  405.  *
  406.  *    consider inlining this...
  407.  */
  408.  
  409.     if (!isalpha (c2) || !isalpha (c1))    return (0);
  410.     if (isupper (c1))            c1 = tolower (c1);
  411.     if (isupper (c2))            c2 = tolower (c2);
  412.  
  413.     return (c1 == c2);
  414. }
  415.  
  416.  
  417.  
  418.  
  419. /*------------------------------*/
  420. /*    usage            */
  421. /*------------------------------*/
  422. void usage (int excode)
  423. {
  424. #define U(x)    fprintf(stderr,x);
  425.  
  426. U("usage: apropos [-P path] [-s section] name ...\n");
  427. U("       -P path     alternative path to databases (MANPATH)\n");
  428. U("       -s section  limit search to single section, not all\n");
  429. U("       name        name of a keyword (any single word).\n");
  430.  
  431. exit (excode);
  432. }
  433.  
  434.